package cn.dansj.common.utils.json;

import cn.dansj.common.utils.reflect.ClassUtils;
import cn.dansj.common.utils.transfer.ArrayUtils;
import cn.dansj.common.utils.transfer.Transformation;
import cn.dansj.common.utils.transfer.Verification;
import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.type.TypeFactory;

import java.lang.reflect.Constructor;
import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

class CommonUtils {
    private static final List<Class<?>> defaultHasNoArgConstructorClass = ArrayUtils.asList(List.class, Map.class);

    private static final List<String> JSONSStyle = Arrays.asList("{}", "[]");
    private static final Map<Class<?>, Boolean> constructorCache = new ConcurrentHashMap<>();
    private static final TypeFactory typeFactory = TypeFactory.defaultInstance();

    public static Feature[] addDefaultFeatures(Class<?> clazz, Feature... features) {
        List<Feature> featureList = ArrayUtils.asList(features);
        featureList.add(Feature.SUPPORT_GSON_ANNOTATION);
        if (!hasNoArgConstructor(clazz)) featureList.add(Feature.SUPPORT_NO_DEFAULT_CONSTRUCT);
        return featureList.toArray(new Feature[]{});
    }

    public static Feature[] addDefaultFeatures(Type type, Feature... features) {
        return addDefaultFeatures(getRawClass(type), features);
    }

    public static JavaType constructType(Type type) {
        return typeFactory.constructType(type);
    }

    public static Class<?> getRawClass(Type type) {
        return constructType(type).getRawClass();
    }

    public static Class<?> getRawClass(TypeReference<?> typeReference) {
        return constructType(typeReference.getType()).getRawClass();
    }

    public static Feature[] addDefaultFeatures(TypeReference<?> typeReference, Feature... features) {
        return addDefaultFeatures(getRawClass(typeReference), features);
    }

    public static Feature[] addDefaultFeatures(Feature... features) {
        List<Feature> featureList = ArrayUtils.asList(features);
        featureList.add(Feature.SUPPORT_GSON_ANNOTATION);
        return featureList.toArray(new Feature[]{});
    }

    public static String addQuoted(String content) {
        return Verification.checkNotNull(content) && Verification.isNotQuoted(content) && !Transformation.isNumeric(content) && !isJsonStyle(content) ? "\"" + content + "\"" : content;
    }

    private static boolean isJsonStyle(String str) {
        if (str.length() < 2) return false;
        char firstChar = str.trim().charAt(0);
        char lastChar = str.trim().charAt(str.trim().length() - 1);
        return JSONSStyle.contains(String.format("%s%s", firstChar, lastChar));
    }

    public static String cleanLongSuffixes(String json) {
        // 匹配数字后跟L/l的格式，但不匹配科学计数法
        return json.replaceAll("(?<![\"'])\\b(\\d+)L\\b(?![\"'])", "$1");
    }

    public static boolean hasNoArgConstructor(Class<?> clazz) {
        if (defaultHasNoArgConstructorClass.stream().anyMatch(e -> e.isAssignableFrom(clazz))) return true;
        return constructorCache.computeIfAbsent(clazz, c -> {
            if (ClassUtils.getConstructor(clazz) != null) return true;
            for (Constructor<?> declaredConstructor : clazz.getDeclaredConstructors()) {
                if (declaredConstructor.getParameterTypes().length == 0) return true;
                if (declaredConstructor.isAnnotationPresent(JsonCreator.class)) return true;
            }
            return false;
        });
    }
}
